package base;

import base.Items.ItemManager;
import base.Skills.SkillManager;
import com.jme3.export.InputCapsule;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule;
import com.jme3.export.Savable;
import java.io.IOException;
import static java.lang.Math.pow;
import java.util.EnumSet;

/**
 * @author Lucas Nunes
 */
public class Character implements Savable {

    private int vitality = 0;
    private int spirit = 0;
    private int strenght = 0;
    private int agility = 0;
    private int dexterity = 0;
    private int intelligence = 0;
    
    private int hp = 0;
    private int sp = 0;
    private int experience = 0;
    
    private ItemManager inventory = new ItemManager();
    private SkillManager skills = new SkillManager();
    private EnumSet<Status> status = EnumSet.noneOf(Status.class);

    public Character() {
    }
    public Character(int vit, int spr, int str, int agi, int dex, int in) {
        this.vitality = vit;
        this.spirit = spr;
        this.strenght = str;
        this.agility = agi;
        this.dexterity = dex;
        this.intelligence = in;
    }
    
    public int getVitality() {
        return this.vitality;
    }
    public void setVitality(int vitality) {
        this.vitality = vitality;
    }
    public void addVitality() {
        this.vitality++;
    }

    public int getSpirit() {
        return this.spirit;
    }
    public void setSpirit(int spirit) {
        this.spirit = spirit;
    }
    public void addSpirit() {
        this.spirit++;
    }

    public int getStrength() {
        return this.strenght;
    }
    public void setStrength(int strenght) {
        this.strenght = strenght;
    }
    public void addStrength() {
        this.strenght++;
    }

    public int getAgility() {
        return this.agility;
    }
    public void setAgility(int agility) {
        this.agility = agility;
    }
    public void addAgility() {
        this.agility++;
    }

    public int getDexterity() {
        return this.dexterity;
    }
    public void setDexterity(int dextery) {
        this.dexterity = dextery;
    }
    public void addDexterity() {
        this.dexterity++;
    }

    public int getIntelligence() {
        return this.intelligence;
    }
    public void setIntelligence(int intelligence) {
        this.intelligence = intelligence;
    }
    public void addIntelligence() {
        this.intelligence++;
    }

    public int getHealthPoints() {
        return this.hp;
    }
    public void setHealthPoints(int hp) {
        this.hp = hp;
    }
    public void addHealthPoints(int hp) {
        this.hp += hp;
    }

    public int getSoulPoints() {
        return this.sp;
    }
    public void setSoulPoints(int sp) {
        this.sp = sp;
    }
    public void addSoulPoints(int sp) {
        this.sp += sp;
    }

    public int getExperience() {
        return this.experience;
    }
    public void setExperience(int experience) {
        this.experience = experience;
    }
    public void addExperience(int experience) {
        this.experience += experience;
    }

    public ItemManager getInventory() {
        return this.inventory;
    }
    
    public SkillManager getSkills() {
        return this.skills;
    }
    
    public EnumSet<Status> getStatus() {
        return this.status.clone();
    }
    public void clearStatus() {
        this.status = EnumSet.noneOf(Status.class);
    }
    public void addStatus(Status status) {
        this.status.add(status);
    }
    public void removeStatus(Status status) {
        this.status.remove(status);
    }

    // Experiencia, level e pontos
    // experiencia por nivel
    // exp = 100.0 * Math.pow(33.0/25.0, level) - 100.0
    public int getLevel() {
        // inverso da formula de experiencia por nivel
        return (int) (Math.log((getExperience() + 100.0) / 100.0) / Math.log(33.0 / 25.0));
    }
    public void setLevel(int level) {
        // integral da formula de experiencia por nivel
        this.experience = (int) (100 * (Math.pow(33.0/25.0, level) / Math.log(33.0/25.0) - level));
    }
    public void addLevel(int level) {
        setLevel(getLevel() + level);
    }
    
    public int totalPontos() {
        return getLevel() + 20;
    }
    public int pontosDisponiveis() {
        return totalPontos() - (getVitality() + getSpirit() + getStrength() + getAgility() + getDexterity() + getIntelligence());
    }

    // Calculo dos atributos
    public int physicAttack() {
        return (int) 
                (10 * pow(1.05, this.getStrength()) + 
                5 * pow(1.05, this.getDexterity()));
    }

    public int physicDefence() {
        return (int) 
                (6 * pow(1.05, this.getStrength()) + 
                3 * pow(1.05, this.getVitality()));
    }

    public int rangeAttack() {
        return (int)
                (12 * pow(1.05, this.getDexterity()));
    }

    public int rangeDefence() {
        return (int) 
                (4 * pow(1.05, this.getDexterity()) + 
                2 * pow(1.05, this.getStrength()) + 
                3 * pow(1.05, this.getVitality()));
    }

    public int magicAttack() {
        return (int) 
                (10 * pow(1.05, this.getIntelligence()) + 
                5 * pow(1.05, this.getSpirit()));
    }

    public int magicDefence() {
        return (int) 
                (6 * pow(1.05, this.getIntelligence()) + 
                3 * pow(1.05, this.getSpirit()));
    }

    public int precision() {
        return (int) (100 * pow(1.015, this.getDexterity()));
    }

    public int attackSpeed() {
        return (int) 
                (100 * pow(1.015, this.getAgility() + this.getDexterity() / 2.0));
    }

    public int movementSpeed() {
        return (int) 
                (100 * pow(1.015, this.getAgility()));
    }

    public int maxHealthPoints() {
        return (int) 
                (70 * pow(1.05, this.getVitality()) + 
                30 * pow(1.05, this.getStrength()));
    }

    public int maxSoulPoints() {
        return (int) 
                (35 * pow(1.05, this.getSpirit()) + 
                15 * pow(1.05, this.getIntelligence()));
    }

    public int ElementalDark() {
        return (int) 
                (2 * pow(1.05, this.skills.getLevelDark()) + 
                this.magicAttack());
    }

    public int ElementalEarth() {
        return (int) 
                (2 * pow(1.05, this.skills.getLevelEarth()) + 
                this.magicAttack());
    }

    public int ElementalFire() {
        return (int) 
                (2 * pow(1.05, this.skills.getLevelFire()) + 
                this.magicAttack());
    }

    public int ElementalLight() {
        return (int) 
                (2 * pow(1.05, this.skills.getLevelLight()) + 
                this.magicAttack());
    }

    public int ElementalWater() {
        return (int) 
                (2 * pow(1.05, this.skills.getLevelWater()) + 
                this.magicAttack());
    }

    public int ElementalWind() {
        return (int) 
                (2 * pow(1.05, this.skills.getLevelWind()) + 
                this.magicAttack());
    }
    // Calculo dos danos

    public void write(JmeExporter ex) throws IOException {
        OutputCapsule out = ex.getCapsule(this);
        
        out.write(vitality, "vitality", 0);
        out.write(spirit, "spirit", 0);
        out.write(strenght, "strength", 0);
        out.write(agility, "agility", 0);
        out.write(dexterity, "dexterity", 0);
        out.write(intelligence, "intelligence", 0);
        out.write(hp, "hp", 0);
        out.write(sp, "sp", 0);
        out.write(experience, "experience", 0);
        out.write(inventory, "inventory", null);
        out.write(skills, "skills", null);
        String[] array = new String[status.size()];
        int i = 0;
        for (Status s : status) {
            array[i] = s.toString();
            i++;
        }
        out.write(array, "status", null);
    }

    public void read(JmeImporter im) throws IOException {
        InputCapsule in = im.getCapsule(this);
        
        vitality = in.readInt("vitality", 0);
        spirit = in.readInt("spirit", 0);
        strenght = in.readInt("strength", 0);
        agility = in.readInt("agility", 0);
        dexterity = in.readInt("dexterity", 0);
        intelligence = in.readInt("intelligence", 0);
        hp = in.readInt("hp", 0);
        sp = in.readInt("sp", 0);
        experience = in.readInt("experience", 0);
        inventory = (ItemManager) in.readSavable("inventory", new ItemManager());
        skills = (SkillManager) in.readSavable("skills", new SkillManager());
        String[] array = in.readStringArray("status", new String[0]);
        status = EnumSet.noneOf(Status.class);
        for (String s : array) {
            status.add(Status.valueOf(s));
        }
    }
}